using Microsoft.Practices.EnterpriseLibrary.Logging;
using NeosSDI.Core.Attributes;
using NeosSDI.Core.Tools;
using System;
using System.Collections.Generic;
using System.Data.Entity.Validation;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Mvc;
using NeosSDI.Core.Manager;

namespace NeosSDI.Core.MVC
{
    /// <summary>
    /// Base controller
    /// </summary>
    public class BaseController : Controller
    {
        /// <summary>
        /// Navigation history
        /// </summary>
        public LimitedQueue<NavigationHistory> NavigationHistories
        {
            get
            {
                if (this.HttpContext.Session["NavigationHistories"] == null)
                    this.HttpContext.Session["NavigationHistories"] = new LimitedQueue<NavigationHistory>(20);
                return (LimitedQueue<NavigationHistory>)this.HttpContext.Session["NavigationHistories"];
            }
        }

        /// <summary>
        /// Method called before action was executed
        /// </summary>
        /// <param name="filterContext">filter context</param>
        protected override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            NavigationHistory navigationHistory = new NavigationHistory()
            {
                UseCase = (UseCase)filterContext.ActionDescriptor.GetCustomAttributes(typeof(UseCase), true).FirstOrDefault(),
                ActionMethod = ((System.Web.Mvc.ReflectedActionDescriptor)(filterContext.ActionDescriptor)).MethodInfo.ToString(),
                ControllerNamespace = filterContext.ActionDescriptor.ControllerDescriptor.ControllerType.FullName,
                ActionParameters = filterContext.ActionParameters
            };

            if (this.HttpContext.Session != null)
            {
                NavigationHistories.Add(navigationHistory);
            }

            base.OnActionExecuting(filterContext);
        }

        /// <summary>
        /// Exception management
        /// Log was writen, then redirect to error action
        /// </summary>
        /// <param name="filterContext">filter context</param>
        protected override void OnException(ExceptionContext filterContext)
        {
            IDictionary<string, object> properties = new Dictionary<string, object>();
            properties.Add("DateTime", DateTime.Now);
            properties.Add("DateTime Formated", DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToLongTimeString());
            properties.Add("StackTrace", filterContext.Exception.StackTrace);
            string exceptionMessage = filterContext.Exception.Message;
            if (filterContext.Exception is DbEntityValidationException)
            {
                DbEntityValidationException entityException = filterContext.Exception as DbEntityValidationException;
                exceptionMessage = "";
                foreach (var validationErrors in entityException.EntityValidationErrors)
                {
                    var entityName = validationErrors.Entry.Entity.ToString();
                    foreach (var validationError in validationErrors.ValidationErrors)
                    {
                        exceptionMessage += string.Format("Property: {0} Error: {1} for Entity: {2}", validationError.PropertyName, validationError.ErrorMessage, entityName);
                    }
                }
            }
            if (filterContext.Exception.InnerException != null)
            {
                properties.Add("InnerException Message", filterContext.Exception.InnerException.Message);
                properties.Add("InnerException StackTrace", filterContext.Exception.InnerException.StackTrace);
                if (filterContext.Exception.InnerException.InnerException != null)
                {
                    properties.Add("InnerException of InnerException Message", filterContext.Exception.InnerException.Message);
                    properties.Add("InnerException of InnerException StackTrace", filterContext.Exception.InnerException.StackTrace);
                }
            }
            properties.Add("NavigationHistories", NavigationHistories.Format());
            Logger.Write(exceptionMessage, "General", 1, 1, TraceEventType.Error, "Technical Error", properties);
            filterContext.ExceptionHandled = false;

            base.OnException(filterContext);
        }

    }
}
